<?
include_once('Dir.php');

//include_once('misc/Time.php');

class File {
	static public $mimeMagic= '/usr/share/file/magic';
	function __construct($filename,$canonicalize=false) {
		if ($filename instanceof File) $filename= $filename->getLocation();
		// turn relative paths into canonicalized absolute pathname
		if ($canonicalize)
			$filename= realpath($filename);
		$this->dir= new Dir(dirname($filename));
		$this->filename= basename($filename);
	}
	function getExtension() {
		$dot= strrpos($this->filename,'.');
		if ($dot=== false) return '';
		return substr($this->filename,$dot+1);
	}
	function getLocation() {
		return $this->dir->getPath().DIRECTORY_SEPARATOR.$this->getFileName();
	}
	function getFileName() {
		return $this->filename;
	}
	function getDir() {
		return $this->dir;
	}
	function exists() {
		return is_file($this->getLocation());
	}
	function isWriteable() {
		return !$this->exists() || is_writable($this->getLocation());
	}
	function setContents($text,$mode='w') {
		if (!($f= fopen($this->getLocation(),$mode)))
			throw new Exception('Cannot open file: '.$this->lastPHPErrorMessage());
		if (fwrite($f,$text)=== false)
			throw new Exception('Cannot write file: '.$this->lastPHPErrorMessage());
		if (!fclose($f))
			throw new Exception('Cannot close file: '.$this->lastPHPErrorMessage());

		return $this;
	}
	function getContents($mode='r') {
		if (!$this->exists())
			throw new Exception('File doesn\'t exists: '.$this->getLocation());
		// empty files return null
		if (($filesize= filesize($this->getLocation()))=== 0)
			return null;
		if (!($handle = fopen($this->getLocation(), $mode)))
			throw new Exception('Error opening file: '.$this->lastPHPErrorMessage());
		if (($content= fread($handle, $filesize))=== false)
			throw new Exception('Error reading file: '.$this->lastPHPErrorMessage());
		if (!fclose($handle))
			throw new Exception('Error closing file: '.$this->lastPHPErrorMessage());
		return $content;
	}

	function remove() {
		if (!unlink($this->getLocation()))
			throw new Exception('Unable to remove file: '.$this->lastPHPErrorMessage());
		return $this;
	}
	function lastChanged() {
		if (!$this->exists()) return null;
		return new DateTime(date(DATE_ATOM,filectime($this->getLocation()))); 
	}

	function getSize() {
		if (!$this->exists()) return null;
		return filesize($this->getLocation());
	}
	function download() {
		$fp = fopen($this->getLocation(), 'rb');
		header('Content-Length: '.$this->getSize());
		header('Content-Disposition: attachment; filename="'.$this->getFileName().'"');
		fpassthru($fp);
		fclose($fp);
		exit;
	}
	function copy($target,$preserve=false) {
		if (!$this->exists()) return false;
		if (!$target instanceof File) $target= new File($target);
		if (empty($preserve)) {
			if (!copy($this->getLocation(),$target->getLocation()))
				throw new Exception('Cannot copy file "'.$this->getLocation().'" to "'.$target->getLocation().'": '.$this->lastPHPErrorMessage());
		}
		else {
			$out= array();
			$ret= 0;
			exec('cp -p '.$this->getLocation().' '.$target->getLocation(),$out,$ret);
			if (!empty($ret))
				throw new Exception('Cannot copy file "'.$this->getLocation().'" to "'.$target->getLocation().'"');
		}
		return $target;
	}
	function move(Dir $dir) {
		$target= $dir->getLocation($this->getFileName());
		if (!rename($this->getLocation(),$target->getLocation()))
			throw new Exception('Cannot move file "'.$this->getLocation().'" to "'.$target->getLocation().'": '.$this->lastPHPErrorMessage());
		$this->dir= $dir;
		return $this;
	}
	function rename(File $file) {
		if (!rename($this->getLocation(),$file->getLocation()))
			throw new Exception('Cannot rename file "'.$this->getLocation().'" to "'.$file->getLocation().'": '.$this->lastPHPErrorMessage());
		return $this;
	}
	function getMimeType() {
		if (!$this->exists())
			throw new Exception('File doesn\'t exists: '.$this->getLocation());
		$finfo = new finfo(FILEINFO_MIME, self::$mimeMagic);
		return $finfo->file($this->getLocation());
	}
	function __toString() {
		return $this->getLocation();
	}
	private function lastPHPErrorMessage() {
		$err= error_get_last();
		return $err['message'];
	}
}